package edu.hawaii.myisern.model;

import java.io.File;
import java.io.StringWriter;
import java.io.FileWriter;
import java.math.BigInteger;
import java.util.List;
import java.util.ArrayList;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import edu.hawaii.myisern.model.collaborations.jaxb.CollaboratingOrganizations;
import edu.hawaii.myisern.model.collaborations.jaxb.Collaboration;
import edu.hawaii.myisern.model.collaborations.jaxb.CollaborationTypes;
import edu.hawaii.myisern.model.collaborations.jaxb.Collaborations;
import edu.hawaii.myisern.model.collaborations.jaxb.OutcomeTypes;
import edu.hawaii.myisern.model.collaborations.jaxb.Years;
import edu.hawaii.myisern.model.organizations.jaxb.AffiliatedResearchers;
import edu.hawaii.myisern.model.organizations.jaxb.Organization;
import edu.hawaii.myisern.model.organizations.jaxb.Organizations;
import edu.hawaii.myisern.model.organizations.jaxb.ResearchKeywords;
import edu.hawaii.myisern.model.researchers.jaxb.Researcher;
import edu.hawaii.myisern.model.researchers.jaxb.Researchers;

/**
 * Provides sample code for loading XML and marshalling it into their JAXB related classes.
 * 
 * @author Philip Johnson
 * @author Lisa Chen
 * @author Randy Cox
 */
public class DataXml {

  /**
   * Returns the passed in instance as a String encoding of its XML representation.
   * 
   * @param context JAXBContext for the XML instance variable.
   * @param data Instance variable to be converted to XML.
   * @return Its XML String representation.
   * @throws Exception if jaxb or IO error is encountered.
   */
  private static String toXml(JAXBContext context, Object data) throws Exception {
    Marshaller marshaller = context.createMarshaller();
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setNamespaceAware(true);
    DocumentBuilder documentBuilder = dbf.newDocumentBuilder();
    Document doc = documentBuilder.newDocument();
    marshaller.marshal(data, doc);
    DOMSource domSource = new DOMSource(doc);
    StringWriter writer = new StringWriter();
    StreamResult result = new StreamResult(writer);
    TransformerFactory tf = TransformerFactory.newInstance();
    Transformer transformer = tf.newTransformer();
    transformer.transform(domSource, result);
    String xmlString = writer.toString();
    return xmlString;
  }

  /**
   * Read records from XML file.
   * 
   * @param filename of XML file to import.
   * @return list of records read from XML file.
   * @throws Exception if jaxb or IO error is encountered.
   * 
   */
  public static List<MyResearcher> readXmlResearchers(String filename) throws Exception {
    Log.enter("DataXml.readXmlResearchers start.");

    // Create jaxb unmarshaller.
    JAXBContext context = JAXBContext.newInstance("edu.hawaii.myisern.model.researchers.jaxb");
    Unmarshaller unmarshaller = context.createUnmarshaller();

    // Open and read file.
    Log.enter("filename = " + filename);
    File file = new File(filename);
    Boolean notNull = (file != null);
    Log.enter("file not null = " + notNull.toString());
    Researchers researchers = (Researchers) unmarshaller.unmarshal(file);
    Log.enter("after unmarchaller");

    // Transfer data from jaxb to our variable.
    List<MyResearcher> myResearchers = new ArrayList<MyResearcher>();
    for (Researcher researcher : researchers.getResearcher()) {
      MyResearcher myResearcher = new MyResearcher();
      myResearcher.setName(researcher.getName());
      myResearcher.setEmail(researcher.getEmail());
      myResearcher.setOrganization(researcher.getOrganization());
      myResearcher.setPictureLink(researcher.getPictureLink());
      myResearcher.setBio(researcher.getBioStatement());
      myResearchers.add(myResearcher);
    }

    Log.enter("DataXml.readXmlResearchers end.");
    return myResearchers;
  }

  /**
   * Saves records to a XML file.
   * 
   * @param filename of XML file to export.
   * @param list list of records to export.
   * @throws Exception if jaxb or IO error is encountered.
   */
  public static void writeXmlResearchers(String filename, List<MyResearcher> list) 
    throws Exception {

    // Transfer data from our variable to Jaxb variable.
    Researchers researchers = new Researchers();
    for (MyResearcher myResearcher : list) {
      Researcher researcher = new Researcher();
      researcher.setName(myResearcher.getName());
      researcher.setEmail(myResearcher.getEmail());
      researcher.setOrganization(myResearcher.getOrganization());
      researcher.setPictureLink(myResearcher.getPictureLink());
      researcher.setBioStatement(myResearcher.getBio());
      researchers.getResearcher().add(researcher);
    }

    // Convert Jaxb varialb to xml string.
    JAXBContext context = JAXBContext.newInstance("edu.hawaii.myisern.model.researchers.jaxb");
    String data = toXml(context, researchers);

    // Write xml string to file.
    FileWriter fileWriter = new FileWriter(filename, false);
    fileWriter.append(data);
    fileWriter.close();
  }

  /**
   * Read records from XML file.
   * 
   * @param filename of XML file to import.
   * @return list of records read from XML file.
   * @throws Exception if jaxb or IO error is encountered.
   * 
   */
  public static List<MyOrganization> readXmlOrganizations(String filename) throws Exception {

    // Create jaxb unmarshaller.
    JAXBContext context = JAXBContext.newInstance("edu.hawaii.myisern.model.organizations.jaxb");
    Unmarshaller unmarshaller = context.createUnmarshaller();

    // Open and read file.
    File file = new File(filename);
    Organizations organizations = (Organizations) unmarshaller.unmarshal(file);

    // Transfer data from jaxb to our variable.
    List<MyOrganization> myOrganizations = new ArrayList<MyOrganization>();
    for (Organization organization : organizations.getOrganization()) {
      MyOrganization myOrganization = new MyOrganization();
      myOrganization.setName(organization.getName());
      myOrganization.setType(organization.getType());
      myOrganization.setContact(organization.getContact());
      myOrganization.setCountry(organization.getCountry());
      AffiliatedResearchers afResearchers = organization.getAffiliatedResearchers();
      for (String afResearcher : afResearchers.getAffiliatedResearcher()) {
        myOrganization.addAffiliatedResearcher(afResearcher);
      }
      myOrganization.setResearchDescription(organization.getResearchDescription());
      ResearchKeywords keywords = organization.getResearchKeywords();
      for (String keyword : keywords.getResearchKeyword()) {
        myOrganization.addResearchKeyword(keyword);
      }
      myOrganization.setHomePage(organization.getHomePage());
      myOrganizations.add(myOrganization);
    }

    return myOrganizations;
  }

  /**
   * Saves records to a XML file.
   * 
   * @param filename of XML file to export.
   * @param list list of records to export.
   * @throws Exception if jaxb or IO error is encountered.
   */
  public static void writeXmlOrganizations(String filename, List<MyOrganization> list)
      throws Exception {

    // Transfer data from our variable to Jaxb variable.
    Organizations organizations = new Organizations();
    for (MyOrganization myOrganization : list) {
      Organization organization = new Organization();
      organization.setName(myOrganization.getName());
      organization.setType(myOrganization.getType());
      organization.setContact(myOrganization.getContact());
      organization.setCountry(myOrganization.getCountry());
      AffiliatedResearchers afResearchers = new AffiliatedResearchers();
      for (String afResearcher : myOrganization.getAffiliatedResearchers()) {
        afResearchers.getAffiliatedResearcher().add(afResearcher);
      }
      organization.setAffiliatedResearchers(afResearchers);
      organization.setResearchDescription(myOrganization.getResearchDescription());
      ResearchKeywords keywords = new ResearchKeywords();
      for (String keyword : myOrganization.getResearchKeywords()) {
        keywords.getResearchKeyword().add(keyword);
      }
      organization.setResearchKeywords(keywords);
      organization.setHomePage(myOrganization.getHomePage());
      organizations.getOrganization().add(organization);
    }

    // Convert Jaxb varialb to xml string.
    JAXBContext context = JAXBContext.newInstance("edu.hawaii.myisern.model.organizations.jaxb");
    String data = toXml(context, organizations);

    // Write xml string to file.
    FileWriter fileWriter = new FileWriter(filename, false);
    fileWriter.append(data);
    fileWriter.close();
  }

  /**
   * Read records from XML file.
   * 
   * @param filename of XML file to import.
   * @return list of records read from XML file.
   * @throws Exception if jaxb or IO error is encountered.
   * 
   */
  public static List<MyCollaboration> readXmlCollaborations(String filename) throws Exception {

    // Create jaxb unmarshaller.
    JAXBContext context = JAXBContext.newInstance("edu.hawaii.myisern.model.collaborations.jaxb");
    Unmarshaller unmarshaller = context.createUnmarshaller();

    // Open and read file.
    File file = new File(filename);
    Collaborations collaborations = (Collaborations) unmarshaller.unmarshal(file);

    // Transfer data from jaxb to our variable.
    List<MyCollaboration> myCollaborations = new ArrayList<MyCollaboration>();
    for (Collaboration collaboration : collaborations.getCollaboration()) {
      MyCollaboration myCollaboration = new MyCollaboration();
      myCollaboration.setName(collaboration.getName());
      myCollaboration.setDescription(collaboration.getDescription());
      CollaboratingOrganizations colOrgs = collaboration.getCollaboratingOrganizations();
      for (String colOrg : colOrgs.getCollaboratingOrganization()) {
        myCollaboration.addOrganization(colOrg);
      }
      Years years = collaboration.getYears();
      for (BigInteger year : years.getYear()) {
        myCollaboration.addYear(year.toString());
      }
      CollaborationTypes types = collaboration.getCollaborationTypes();
      for (String type : types.getCollaborationType()) {
        myCollaboration.addType(type);
      }
      OutcomeTypes outcomes = collaboration.getOutcomeTypes();
      for (String outcome : outcomes.getOutcomeType()) {
        myCollaboration.addOutcome(outcome);
      }
      myCollaborations.add(myCollaboration);
    }
    return myCollaborations;
  }

  /**
   * Saves records to a XML file.
   * 
   * @param filename of XML file to export.
   * @param list list of records to export.
   * @throws Exception if jaxb or IO error is encountered.
   */
  public static void writeXmlCollaborations(String filename, List<MyCollaboration> list)
      throws Exception {

    // Transfer data from our variable to Jaxb variable.
    Collaborations collaborations = new Collaborations();
    for (MyCollaboration myCollaboration : list) {
      Collaboration collaboration = new Collaboration();
      collaboration.setName(myCollaboration.getName());
      collaboration.setDescription(myCollaboration.getDescription());
      CollaboratingOrganizations colOrgs = new CollaboratingOrganizations();
      for (String colOrg : myCollaboration.getOrganizations()) {
        colOrgs.getCollaboratingOrganization().add(colOrg);
      }
      collaboration.setCollaboratingOrganizations(colOrgs);
      Years years = new Years();
      for (String yearStr : myCollaboration.getYears()) {
        years.getYear().add(new BigInteger(yearStr));
      }
      collaboration.setYears(years);
      CollaborationTypes types = new CollaborationTypes();
      for (String type : myCollaboration.getTypes()) {
        types.getCollaborationType().add(type);
      }
      collaboration.setCollaborationTypes(types);
      OutcomeTypes outcomes = new OutcomeTypes();
      for (String outcome : myCollaboration.getOutcomes()) {
        outcomes.getOutcomeType().add(outcome);
      }
      collaboration.setOutcomeTypes(outcomes);
      collaborations.getCollaboration().add(collaboration);
    }

    // Convert Jaxb varialb to xml string.
    JAXBContext context = JAXBContext.newInstance("edu.hawaii.myisern.model.collaborations.jaxb");
    String data = toXml(context, collaborations);

    // Write xml string to file.
    FileWriter fileWriter = new FileWriter(filename, false);
    fileWriter.append(data);
    fileWriter.close();
  }

}
